iT邦幫忙

2023 iThome 鐵人賽

DAY 4
0
Modern Web

React 走出新手村 系列 第 4

React 走出新手村-回顧發展歷史

  • 分享至 

  • xImage
  •  

React講古

要了解 React 除了基礎的概念,了解他們的發展史也是很重要的一環,整個的發展先後順序就如圖面一樣。
https://ithelp.ithome.com.tw/upload/images/20230901/201290204Xtg9VtFuf.jpg
從圖面可知,本來的 React 就是透過 Javascript 去創造 virtual dom 節點的套件來運作而已。

那麼虛擬dom是怎麼產生的呢?

下面是用 Typescript 基本推倒的過程:

// 大概簡單的處理type -> html tag, props應該知道是什麼吧
interface VirtualElement {
  type: string;
  props: Props;
}

interface Props {
  [key: string]: any;
  children?: VirtualElement[] | string[];
}

// 你可以把它想像成React後面再幫我們處理的動作
class AnalysisUI {
  private root: HTMLElement;
  private virtualDom: VirtualElement | null;

  constructor(rootSelector: string) {
    this.root = document.querySelector(rootSelector) as HTMLElement;
    this.virtualDom = null;
  }

  render(element: VirtualElement): void {
    this.virtualDom = element;
    this.update();
  }

  private update(): void {
    if (this.virtualDom) {
      const newDom = this.createDomElement(this.virtualDom);
      this.root.innerHTML = '';
      this.root.appendChild(newDom);
    }
  }

  private createDomElement(virtualElement: VirtualElement): HTMLElement {
    const { type, props } = virtualElement;
    const dom = document.createElement(type);
    // 這裡有透過chatGPT縮短過,可以直接套入html使用,跑起來是沒問題的
    Object.keys(props)
      .filter(prop => prop !== 'children')
      .forEach(name => {
        dom[name] = props[name];
      });

    if (props.children) {
      props.children.forEach(child => {
        if (child instanceof HTMLElement) {
          dom.appendChild(child);
        } else if (typeof child === 'string') {
          dom.appendChild(document.createTextNode(child));
        } else if (child) {
          // 處理子層的子層
          dom.appendChild(this.createDomElement(child));
        }
      });
    }

    return dom;
  }
}

// 建立模擬 react 的 analysisUI
const analysisUI = new AnalysisUI('#app');

// 建立虛擬DOM元素,就是類似React.component會產出來的東西
// 然後再拿這個物件去做diff的處理
const appElement: VirtualElement = {
  type: 'div',
  props: {
    className: 'app',
    children: [
      { type: 'h1', props: { innerText: 'Hello, world!' } },
      { type: 'p', props: { innerText: '一定是大拇指啦!' } }
    ]
  }
};

// 渲染虛擬DOM,可以把它想成是ReactDom在跑的那個步驟
analysisUI.render(appElement);

當然,這裡沒有仔細去處理效能優化的問題,只是讓大家理解虛擬DOM是怎麼產生的,如果直接套用的話就會得到虛擬dom產生的畫面,至於優缺點在你們剛開始學習React的時候都讀過了,我這裡就不再贅述。

加入JSX

在他們使用了jsx之後,讓我們可以將html的tag塞進js裡面,然後透過繼承React.component的方式去創造virtual dom的生命週期。

他的好處就是能透過{} 在html dom 節點當中自由切換使用 js,這樣的做法無疑是一大變革,在其他框架都必須用自己的 framework 語法處理 loop, if, … 的問題時(ex: v-for, v-if, *ngFor, *ngIf….),他提供了一個共用標準 『js語法』 ,也就是你js怎麼處理,你的html tag就怎麼處理,不用想說要用哪個語法來處理上述問題,{}挖洞下去就是可以直接切成 javascript 語法,最後再透過babel轉譯為純 JavaScript。

// 我相信大家應該看過很多次了
const hello = <h1>Hello</h1>;
// 基本的挖洞
const name = "John";
const greeting = <p>Hello, {name}!</p>;
// 套在attr的使用
const handleClick = () => alert("晚安,瑪卡巴卡!");
const buttonElement = <button onClick={handleClick}>點擊</button>;
// React早期Class component
class MyClassComponent extends React.Component {
  render() {
    return (
      <div>
        <h1>早安,瑪卡巴卡!</h1>
      </div>
    );
  }
}
// Functional component 這裡記住要大寫,大寫才會吃到React的生命週期
const MyFuncComponent = () => (<p>晚安,瑪卡巴卡</p>);
// 你可以在 JSX 中引用 React 元件,以組合和嵌套它們來構建複雜的 UI。
const element = (
  <div>
    <h1>Welcome to My App</h1>
    <MyComponent />
  </div>
);

這就是早期的class component盛行的作法,我也是經歷轉換期的洗禮,學了一圈hooks的教學後,找工作面試都在問你class component的問題,所以學新的技術真的是在為以後的工作鋪路。

hook的改進

再來的大變革就是現在普遍熟知的Hooks了,在 React 16.8 版本中,全面支持Hooks,Hooks 是一種新的 API,讓開發者可以在不使用 class component 的情況下使用狀態(state)和其他 React 功能,這種方式更簡潔、可讀性更高,並且使組件邏輯更容易共享,詳細的的演變可以參考React conf 2018,裡面有示範了很多class component如何替換成hooks來對應生命週期的。

總結

今天的內容就到這裡,那麼接下來我們來嘗試理解幾個常用到的hooks。

給全新手的大禮包

React基本Hook教學


上一篇
React 走出新手村-包版工具的設定
下一篇
React 走出新手村-深入useState
系列文
React 走出新手村 31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言